<?php

/**
 * This is the model class for table "user".
 *
 * The followings are the available columns in table 'user':
 * @property integer $id_user
 * @property integer $id_group
 * @property integer $id_user_role
 * @property string $username
 * @property string $password
 * @property string $firstname
 * @property string $lastname
 * @property string $email
 * @property integer $status
 * @property integer $loginattempts
 * @property string $authy_id
 */
class User extends CActiveRecord
{
	const STATUS_ACTIVE = 1;
	const STATUS_SUSPENDED = 0;
	
	public $EnP = true;
	
	/**
	 * Returns the static model of the specified AR class.
	 * @param string $className active record class name.
	 * @return User the static model class
	 */
	public static function model($className=__CLASS__)
	{
		return parent::model($className);
	}

	/**
	 * @return string the associated database table name
	 */
	public function tableName()
	{
		return 'user';
	}
	
	/**
	 * @return array validation rules for model attributes.
	 */
	public function rules()
	{
		// NOTE: you should only define rules for those attributes that
		// will receive user inputs.
		return array(
			array('firstname, lastname, email, username, password, status', 'required'),
			array('firstname, lastname, email, username, status', 'length', 'max' => 50),
			array('id_group, id_user_role, status, loginattempts', 'numerical', 'integerOnly'=>true),
			array('username', 'unique', 'className' => __CLASS__, 'attributeName' => 'username', 'message' => 'Username already exists'),
			array('username, password, firstname, lastname, email', 'safe'),
			array('email', 'email'),
			array('password, username', 'length', 'min' => 5),
			// The following rule is used by search().
			// Please remove those attributes that should not be searched.
			array('id_user, id_group, id_user_role, username, password, firstname, lastname, email, status, loginattempts', 'safe', 'on'=>'search'),
			array('id_user, id_group, id_user_role, username, firstname, lastname, email, status, loginattempts', 'safe', 'on'=>'ajaxEdit'),
		);
	}

	/**
	 * @return array relational rules.
	 */
	public function relations()
	{
		// NOTE: you may need to adjust the relation name and the related
		// class name for the relations automatically generated below.
		return array(
			'Role' => array(self::BELONGS_TO, 'UserRole', 'id_user_role'),
			'IndividualOption' => array(self::HAS_ONE, 'IndividualConfig', 'id_user')
		);
	}

	/**
	 * @return array customized attribute labels (name=>label)
	 */
	public function attributeLabels()
	{
		return array(
			'id_user' => t('info', 'Id User'),
			'id_group' => t('info', 'Id Group'),
			'id_user_role' => t('info', 'Id User Role'),
			'username' => t('info', 'Username'),
			'password' => t('info', 'Password'),
			'firstname' => t('info', 'First Name'),
			'lastname' => t('info', 'Last Name'),
			'email' => t('info', 'Email'),
			'status' => t('info', 'Status'),
			'loginattempts' => t('info', 'Loginattempts'),
		);
	}

	/**
	 * Retrieves a list of models based on the current search/filter conditions.
	 * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
	 */
	public function search()
	{
		// Warning: Please modify the following code to remove attributes that
		// should not be searched.

		$criteria=new CDbCriteria;

		$criteria->compare('id_user',$this->id_user);
		$criteria->compare('id_group',$this->id_group);
		$criteria->compare('id_user_role',$this->id_user_role);
		$criteria->compare('username',$this->username,true);
		$criteria->compare('password',$this->password,true);
		$criteria->compare('firstname',$this->firstname,true);
		$criteria->compare('lastname',$this->lastname,true);
		$criteria->compare('email',$this->email,true);
		$criteria->compare('status',$this->status);
		$criteria->compare('loginattempts',$this->loginattempts);
		$criteria->compare('authy_id',$this->authy_id);

		return new CActiveDataProvider($this, array(
			'criteria'=>$criteria,
			'pagination' => array(
				'pageSize'=> app()->user->getData()->getIndividualConfig()->getPagination()
			)
		));
	}
	
	public function beforeSave() {
//		if ($this->isNewRecord){
			$this->passwordEncode();
//		}
		return true;
	}
	
	public function delete()
	{
		if($this->isLastSupreme()){
			$this->addError('Supreme', 'This is the last one user under Supreme Role, delete operate canceled');
			return false;
		}
		
		return parent::delete();
	}
	
	public function isLastSupreme()
	{
		if(!$this->Role){
			return false;
		}
		if($this->Role->supreme != 1){
			return false;
		}
		
		return $this->countByAttributes(array('id_user_role' => $this->Role->id_user_role)) <= 1;
	}
	
	public function passwordEncode()
	{
		if(!empty($this->password)){
			if($this->EnP){
				$passwordHasher = new PasswordHash(8, false);
				$this->password = $passwordHasher->HashPassword($this->password);
			}
		}
	}
	
	public function checkPassword($passwordPlain)
	{
		if(!empty($this->password)){
			$passwordHasher = new PasswordHash(8, false);
			return $passwordHasher->CheckPassword($passwordPlain, $this->password);
		}
		
		return false;
	}
	
	
	public function __get($key)
	{
		$action = 'get' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key)));
		if(method_exists($this, $action)){
			return $this->$action();
		}
		
		return parent::__get($key);
	}
	public function getFullName()
	{
		return $this->firstname . ' ' . $this->lastname;
	}
	
	public function getStatusTxt()
	{
		return $this->status == self::STATUS_ACTIVE? 'Active' : 'Suspended';
	}
	
	public function getCountAllowWhmAccount()
	{
		if(empty($this->Role)){
			return 0;
		}else{
			return count(
				$this->Role->UserRolePermAccountAllow
			);
		}
	}
	
	public function getCountCpanelAccount()
	{
		if(empty($this->Role)){
			return 0;
		}
		$allowAccounts = $this->Role->UserRolePermAccountAllow;
		if(empty($allowAccounts)){
			return 0;
		}
		$count = 0;
		foreach($allowAccounts as $a){
			if(!empty($a->WhmAccount)){
				$count += count($a->WhmAccount->CpanelAccounts);
			}
		}
		return $count;
	}
	
	const AUTHY_API_KEY = '6e536c48ac3b7633001902a38917bfd4';
	public function authy($countryCode, $cellphone)
	{
		require_once 'authy/Authy.php';
//		$authyApi = new Authy_Api(self::AUTHY_API_KEY, 'http://sandbox-api.authy.com');
		$authyApi = new Authy_Api(self::AUTHY_API_KEY);
		$authyResult = $authyApi->registerUser($this->email, $cellphone, $countryCode);
		if($authyResult->ok()){
			$user = self::model()->findByPk($this->id_user);
			$user->authy_id = $authyResult->id();
			$user->EnP = false;
			return $user->save();
		}else{
			foreach($authyResult->errors() as $field => $message){
				$this->addError('Authy', "$field: $message");
			}
			return false;
		}
	}
	
	public function disableAuthy()
	{
		$curl = curl_init();
		curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($curl, CURLOPT_POST, 1);
		curl_setopt($curl, CURLOPT_URL, "https://api.authy.com/protected/json/users/delete/{$this->authy_id}");
		curl_setopt($curl, CURLOPT_POSTFIELDS, array('api_key' => self::AUTHY_API_KEY));
		$result = curl_exec($curl);
		if($result === false){
			return false;
		}
		$result = json_decode($result);
		
		// do not put in else{}? Because Authy uses the cell phone number as the unique identifier, So two different emails with the same cell would have the same authy id. if disable failed, it may have been disabled by some else, just remove it from our db
		$user = self::model()->findByPk($this->id_user);
		$user->authy_id = '';
		$user->EnP = false;
		return $user->save();
		
		if($result->success == 'false'){
//			foreach($result->errors as $field => $message){
//				$this->addError('disableAuthy', "$field: $message");
//			}
//			return false;
		}else{
//			$user = self::model()->findByPk($this->id_user);
//			$user->authy_id = '';
//			$user->EnP = false;
//			return $user->save();
		}
	}
	
	public function sendAuthySms()
	{
		$curl = curl_init();
		curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
//		curl_setopt($curl, CURLOPT_POST, 1);
		curl_setopt($curl, CURLOPT_URL, "https://api.authy.com/protected/json/sms/{$this->authy_id}?api_key=" . self::AUTHY_API_KEY);
//		curl_setopt($curl, CURLOPT_POSTFIELDS, array('api_key' => self::AUTHY_API_KEY));
		$result = curl_exec($curl);
		if($result === false){
			return false;
		}
		$result = json_decode($result);
		if($result->success == 'false'){
			foreach($result->errors as $field => $message){
				$this->addError('sendAuthySms', "$field: $message");
			}
			return false;
		}else{
			return true;
		}
	}
	
	public function authyVerifyTokens($tokens)
	{
		require_once 'authy/Authy.php';
		$authyApi = new Authy_Api(self::AUTHY_API_KEY);
		$verification = $authyApi->verifyToken($this->authy_id, $tokens);
		
		if($verification->ok()){
			return true;
		}else{
			foreach($verification->errors() as $field => $message){
				$this->addError('authyVerifyTokens', "$field: $message");
			}
			return false;
		}
	}

	public function getFinalAccessdAccountIds()
	{
		$accessAccountId = array();
			
		$groupAccess = app()->user->getGroupAccess();
		$accountAccess = app()->user->getAccountAccess();
		foreach($groupAccess as $gc){
			if(!empty($gc->Group)){
				foreach($gc->Group->WhmAccount as $account){
					if($gc->allow_or_deny == 1){
						$accessAccountId[] = $account->id_account;
					}
				}
			}
		}
		foreach($accountAccess as $ac){
			if($ac->allow_or_deny == 1){
				$accessAccountId[] = $ac->id_account;
			}else{
				$accessAccountId = array_diff($accessAccountId, array($ac->id_account));
			}
		}
		
		return $accessAccountId;
	}
	
	public function getFinalAccessdGroupIds()
	{
		$accessGroupId = array();
			
		$groupAccess = app()->user->getGroupAccess();
		foreach($groupAccess as $gc){
			if(!empty($gc->Group)){
				$accessGroupId[] = $gc->Group->id_group;
			}
		}
		return $accessGroupId;
	}
	
	public function getIndividualConfig()
	{
		return empty($this->IndividualOption)? new IndividualConfig() : $this->IndividualOption;
	}
	
	public function initIndividualConfig()
	{
		$individualConfig = new IndividualConfig();
		$individualConfig->id_user = $this->id_user;
		$individualConfig->allow_reset_restrict_ip_byemail = app()->params['INDIVIDUAL_SETTING']['ALLOW_RESET_RESTRICTIP_BYEMAIL'];
		$individualConfig->language = app()->params['INDIVIDUAL_SETTING']['LANGUAGE'];
		$individualConfig->wiki_help = app()->params['INDIVIDUAL_SETTING']['WIKI_HELP'];
		$individualConfig->pagination = app()->params['INDIVIDUAL_SETTING']['PAGINATION'];
		return $individualConfig->save();
	}
	
	public function renderListActionButtons()
	{
		return '
			<div class="btn-group">
				<button class="btn btn-info actions dropdown-toggle" data-toggle="dropdown">
					'. t('buttons', 'Actions') .'
					<span class="caret"></span>
				</button>
				<ul class="dropdown-menu">
					' . (empty($this->authy_id)? 
						'<li class="user_authy"><a id="setup" href="'.(empty($this->id_user)? 'javascript:void(0);' : url('user/authy', array('id_users' => array($this->id_user)))).'">'. t('buttons', 'Setup 2-Factor Auth') .'</a></li>' 
						:
						'<li class="user_authy"><a id="disable" href="javascript:void(0);">'. t('buttons', 'Disable 2-Factor Auth') .'</a></li>') . '
					<li class="user_edit"><a href="#">'. t('buttons', 'Edit User') .'</a></li>
					<li class="user_delete"><a href="#">'. t('buttons', 'Delete User') .'</a></li>
				</ul>
				
				<div class="disableauthy_confirm_btn hide">
					<a class="btn btn-small disableauthy_confirm"><i class="icon-ok"></i>'. t('buttons', 'Confirm Disable') .'</a>
					<a class="btn btn-small disableauthy_cancel"><i class="icon-remove"></i>'. t('buttons', 'Cancel') .'</a>
				</div>
				
				<div class="delete_confirm_btn hide">
					<a class="btn btn-small delete_confirm"><i class="icon-ok"></i>'. t('buttons', 'Confirm Delete') .'</a>
					<a class="btn btn-small delete_cancel"><i class="icon-remove"></i>'. t('buttons', 'Cancel') .'</a>
				</div>
			</div>
		';
	}
	
	public function increaseLoginattempts()
	{
		$oldEp = $this->EnP;
		$this->EnP = false;
		$this->loginattempts++;
		$ret = $this->save();
		$this->EnP = $oldEp;
		
		return $ret;
	}
	
	public function resetLoginattempts()
	{
		$oldEp = $this->EnP;
		$this->EnP = false;
		$this->loginattempts = 0;
		$ret = $this->save();
		$this->EnP = $oldEp;
		
		return $ret;		
	}
	
	public function suspend()
	{
		$oldEp = $this->EnP;
		$this->EnP = false;
		$this->status = self::STATUS_SUSPENDED;
		$ret = $this->save();
		$this->EnP = $oldEp;
		
		return $ret;		
	}
	
	public function active()
	{
		$oldEp = $this->EnP;
		$this->EnP = false;
		$this->status = self::STATUS_ACTIVE;
		$ret = $this->save();
		$this->EnP = $oldEp;
		
		return $ret;		
	}
}